import os, sys

from PyQt5 import QtGui
from PyQt5.QtWidgets import *

from strange_io.text import StrangeText

from protolib.gui_utils.pyqt5_messageboxes import (
    show_info_messagebox,
    show_critical_messagebox,
    show_question_messagebox
)

class MainWindow(QMainWindow):
    def __init__(self, args):
        super().__init__()

        self.setWindowIcon(QtGui.QIcon('icon.png'))
        self.setWindowTitle("Strange Text Editor - Strange I/O")

        #region
        menuBar = self.menuBar()
        #region
        self.fileMenu = QMenu("&File", self)
        menuBar.addMenu(self.fileMenu)
        #region
        newFileAction = QAction("&New", self)
        newFileAction.setShortcut("Ctrl+N")
        newFileAction.setStatusTip('Create new file and clear change buffer')
        newFileAction.triggered.connect(self.new_file)
        self.fileMenu.addAction(newFileAction)
        #endregion
        #region
        openFileAction = QAction("&Open", self)
        openFileAction.setShortcut("Ctrl+O")
        openFileAction.setStatusTip('Load a file from disk')
        openFileAction.triggered.connect(self.user_open_file)
        self.fileMenu.addAction(openFileAction)
        #endregion
        #region
        saveAction = QAction("&Save", self)
        saveAction.setShortcut("Ctrl+S")
        saveAction.setStatusTip('Save the file buffer to disk')
        saveAction.triggered.connect(self.save_file)
        self.fileMenu.addAction(saveAction)
        #endregion
        #region
        saveAsAction = QAction("&Save As", self)
        saveAsAction.setShortcut("Ctrl+Shift+S")
        saveAsAction.setStatusTip('Change current file and save the file buffer to disk')
        saveAsAction.triggered.connect(self.save_as_file)
        self.fileMenu.addAction(saveAsAction)
        #endregion
        #region
        importAction = QAction("&Import", self)
        importAction.setShortcut("Ctrl+I")
        importAction.setStatusTip('Import a plain text document')
        importAction.triggered.connect(self.import_file)
        self.fileMenu.addAction(importAction)
        #endregion
        #region
        exportAction = QAction("&Export", self)
        exportAction.setShortcut("Ctrl+E")
        exportAction.setStatusTip('Export a plain text document')
        exportAction.triggered.connect(self.export_file)
        self.fileMenu.addAction(exportAction)
        #endregion
        self.fileMenu.addSeparator()
        #region
        quitAction = QAction("&Quit", self)
        quitAction.setShortcut("Ctrl+Q")
        quitAction.setStatusTip('Leave The App')
        quitAction.triggered.connect(self.close)
        self.fileMenu.addAction(quitAction)
        #endregion
        #endregion
        #region
        self.editMenu = QMenu("&Edit", self)
        menuBar.addMenu(self.editMenu)
        #region
        undoAction = QAction("&Undo", self)
        undoAction.setShortcut("Ctrl+Z")
        undoAction.setStatusTip('Undo last change')
        self.editMenu.addAction(undoAction)
        #endregion
        #region
        redoAction = QAction("&Redo", self)
        redoAction.setShortcut("Ctrl+Y")
        redoAction.setStatusTip('Redo last change')
        self.editMenu.addAction(redoAction)
        #endregion
        self.editMenu.addSeparator()
        #region
        cutAction = QAction("&Cut", self)
        cutAction.setShortcut("Ctrl+X")
        self.editMenu.addAction(cutAction)
        #endregion
        #region
        copyAction = QAction("&Copy", self)
        copyAction.setShortcut("Ctrl+C")
        self.editMenu.addAction(copyAction)
        #endregion
        #region
        pasteAction = QAction("&Paste", self)
        pasteAction.setShortcut("Ctrl+V")
        self.editMenu.addAction(pasteAction)
        #endregion
        #endregion
        #endregion

        #region
        self.layout = QVBoxLayout()

        self.widget = QWidget()
        self.widget.setLayout(self.layout)

        self.text_edit = QPlainTextEdit()
        self.text_edit.textChanged.connect(self.onTextEdited)
        undoAction.triggered.connect(self.text_edit.undo)
        redoAction.triggered.connect(self.text_edit.redo)
        self.layout.addWidget(self.text_edit)

        self.save_button = QPushButton()
        self.save_button.setText('Save')
        self.save_button.clicked.connect(self.save_file)
        self.layout.addWidget(self.save_button)
        #endregion

        #region
        self.stext = StrangeText()
        self.edited = False
        self.current_file = None
        #endregion

        self.setCentralWidget(self.widget)

        if args.file_path:
            try:
                self.open_file(args.file_path)
            except os.OSError as e:
                show_critical_messagebox(e.__class__.__name__, str(e))

    def save_file(self):
        if self.current_file:
            try:
                content = self.text_edit.toPlainText()
                self.stext.load(content)
                self.stext.dump_file(self.current_file)
                self.edited = False
            except (ValueError, OSError) as e:
                show_critical_messagebox(e.__class__.__name__, str(e))
        else:
            self.save_as_file()

    def save_as_file(self):
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        file_path, _ = QFileDialog.getSaveFileName(self, "Save file", "", "Strange Text Documents (*.stext *.stxt);;Strange I/O Documents (*.strange *.sio);;All Files (*)", options=options)
        if file_path:
            try:
                content = self.text_edit.toPlainText()
                self.current_file = file_path
                self.stext.load(content)
                self.stext.dump_file(self.current_file)
                show_info_messagebox("Info", "File saved successfully!")
            except (ValueError, OSError) as e:
                show_critical_messagebox(e.__class__.__name__, str(e))

        self.edited = False

    def new_file(self):
        if self.edited:
            ask_overwrite_buffer = show_question_messagebox('Create New File', 'Are you sure you want to delete the unsaved buffer?', QMessageBox.Yes|QMessageBox.No)
            if ask_overwrite_buffer == QMessageBox.No:
                return

        self.text_edit.clear()
        self.stext = StrangeText()
        self.current_file = None
        self.edited = False

    def user_open_file(self):
        if self.edited:
            ask_overwrite_buffer = show_question_messagebox('Open File', 'Are you sure you want to overwrite the unsaved buffer?', QMessageBox.Yes|QMessageBox.No)
            if not ask_overwrite_buffer:
                return

        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        file_path, _ = QFileDialog.getOpenFileName(self, "Open file", "", "Strange Text Documents (*.stext *.stxt);;Strange I/O Documents (*.strange *.sio);;All Files (*)", options=options)
        if file_path:
            try:
                self.open_file(file_path)
            except (ValueError, TypeError) as e:
                show_critical_messagebox(e.__class__.__name__, str(e))

        self.edited = False

    def open_file(self, file_path):
        self.stext.load_file(str(file_path))
        content = self.stext.dump()
        self.text_edit.clear()
        self.text_edit.appendPlainText(content)
        self.current_file = file_path

        self.edited = False

    def import_file(self):
        if self.edited:
            ask_overwrite_buffer = show_question_messagebox('Import File', 'Are you sure you want to overwrite the unsaved buffer?', QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes
            if not ask_overwrite_buffer:
                return

        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        file_path, _ = QFileDialog.getOpenFileName(self, "Open file", "", "Plain Text Documents (*.txt);;All Files (*)", options=options)
        if file_path:
            with open(file_path) as txt:
                content = txt.read()
                self.stext.load(content)
                self.text_edit.clear()
                self.text_edit.appendPlainText(content)

        self.edited = False

    def export_file(self):
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        file_path, _ = QFileDialog.getSaveFileName(self, "Export file", "", "Plain Text Documents (*.txt);;All Files (*)", options=options)
        if file_path:
            with open(file_path, 'w') as txt:
                txt.write(self.text_edit.toPlainText())

    def onTextEdited(self):
        self.edited = True

    def closeEvent(self, event):
        if self.edited:
            if show_question_messagebox('Unsaved Changes', 'Would you like to save the changes before exiting?', QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes:
                self.save_file()
        print('Good bye!')

def main(args):
    app = QApplication(sys.argv)
    window = MainWindow(args)
    window.show()
    app.exec()
